package com.easymin.weixin.controller.v5;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.WebUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.easymin.weixin.common.MediaUtil;
import com.easymin.weixin.common.PhoneNumberHelper;
import com.easymin.weixin.common.WxUtils;
import com.easymin.weixin.common.api.DaijiaApi;
import com.easymin.weixin.common.api.ErrandApi;
import com.easymin.weixin.common.api.PassengerApi;
import com.easymin.weixin.common.api.ZhuanApi;
import com.easymin.weixin.common.api.ZhuanXianApi;
import com.easymin.weixin.common.transport.Error;
import com.easymin.weixin.common.transport.Result;
import com.easymin.weixin.common.transport.ResultVo;
import com.easymin.weixin.controller.v5.utils.ErrorMapV5;
import com.easymin.weixin.controller.v5.utils.ResultV5;
import com.easymin.weixin.entity.Order;
import com.easymin.weixin.entity.WxAccount;
import com.easymin.weixin.entity.WxApplication;
import com.easymin.weixin.entity.passenger.Passenger;
import com.easymin.weixin.manager.ErrandManager;
import com.easymin.weixin.manager.FreightManager;
import com.easymin.weixin.manager.WxAccountManager;
import com.easymin.weixin.manager.WxApplicationManager;
import com.google.common.base.Preconditions;

/**
 * 跑腿信息请求控制器
 * 
 * @author zane
 *
 */
@Controller
@RequestMapping("v5/paotui/")
public class PaoTuiController {
	
	private static final String WX_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}";

	private static final String WX_JSAPI_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={access_token}&type=jsapi";

	@Autowired
	private WxApplicationManager wxApplicationManager;

	@Autowired
	private ErrandManager errandManager;

	@Autowired
	private WxAccountManager wxAccountManager;
	
	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private DaijiaApi daijiaApi;

	@Autowired
	private ErrandApi errandApi;

	@Autowired
	private PassengerApi passengerApi;

	@Autowired
	private ZhuanApi zhuanApi;

	@Autowired
	private FreightManager freightManager;

	@Autowired
	private ZhuanXianApi zhuanXianApi;

	/**
	 * 跑腿预算费用
	 * 
	 * @param appKey
	 *            系统key
	 * @param areaId
	 *            收费ID
	 * @param time
	 *            前端预算的时间（分钟）
	 * @param mileage
	 *            前端预算的公里
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "calculationPrice", method = { RequestMethod.GET })
	public ResultV5 calculationPrice(@RequestParam(required = true, value = "appKey") String appKey,
			@RequestParam(required = true, value = "areaId") Long areaId,
			@RequestParam(required = false, value = "time") Integer time,
			@RequestParam(required = false, value = "mileage") Double mileage) {

		WxApplication wxApplication = wxApplicationManager.findByAppKey(appKey);
		String server = wxApplication.getAddress();

		ResultV5 result = null;
		JSONObject json = daijiaApi.getPaoTuiPrice(server, areaId, time, mileage);
		if (json.getIntValue("code") == 0) {
			result = ErrorMapV5.ERR_SUCCESS.clone();
			result.setData(json.getJSONObject("data"));
		} else {
			result = ErrorMapV5.ERR_PAOTUI_CALCULATION_PRICE;
			result.setErrorMsg(String.valueOf(json.get("message")));
		}
		return result;
	}

	/**
	 * 跑腿获取用户优惠券
	 * 
	 * @param appKey
	 *            系统Key
	 * @param passengerId
	 *            用户ID
	 * @param couponTypeId
	 *            优惠券类型Id
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "getCoupons", method = { RequestMethod.GET })
	public ResultV5 getPaoTuiCoupons(@RequestParam(required = true, value = "appKey") String appKey,
			@RequestParam(required = true, value = "passengerId") Long passengerId,
			@RequestParam(required = false, value = "couponTypeId") Long couponTypeId) {

		WxApplication wxApplication = wxApplicationManager.findByAppKey(appKey);
		String server = wxApplication.getAddress();

		JSONObject json = daijiaApi.getPaoTuiCoupons(server, passengerId, couponTypeId);

		ResultV5 result = null;
		if (null != json) {
			if (json.getIntValue("code") == 0) {
				result = ErrorMapV5.ERR_SUCCESS.clone();
				result.setData(json.getJSONArray("data"));
				return result;
			}
		}
		return ErrorMapV5.ERR_GET_PAOTUI_COUPONS;
	}

	/**
	 * 获取跑腿评价
	 * 
	 * @param appKey appKey
	 * @param orderId 订单号
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "getReview", method = { RequestMethod.GET })
	public ResultV5 getReview(
			@RequestParam(required = true, value = "appKey") String appKey,
			@RequestParam(required = true, value = "orderId") Long orderId) {

		JSONObject json = errandApi.getReviewV5(orderId, appKey);
		ResultV5 result = ErrorMapV5.ERR_SUCCESS.clone();
		result.setData(json.getJSONObject("data"));
		return result;
	}

	/**
	 * 跑腿上传图片
	 * @param req 请求对象
	 * @param imgFile 文件
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@RequestMapping(value="upload", method={RequestMethod.POST})
	public ResultV5 uploadPhoto(HttpServletRequest req, @RequestParam("photo") MultipartFile imgFile) throws Exception {
		String moduleName = imgFile.getOriginalFilename();
		ResultV5 result = ErrorMapV5.ERR_SUCCESS.clone();
		if (MediaUtil.isPicture(moduleName, "")) {
			String bathPath = WebUtils.getRealPath(req.getSession().getServletContext(), "/");
			Date now = new Date();
			String filestr = "upload/photos/" 
					+ now.getTime()
					+ moduleName.substring(moduleName.lastIndexOf("."), moduleName.length());
			File file = new File(bathPath, filestr);

			if (!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}

			try {
				File tempDest = new File(System.getProperty("java.io.tmpdir"),
						"upload_" + String.valueOf(System.nanoTime()) + ".tmp");
				imgFile.transferTo(tempDest); // 上传到临时文件中
				FileUtils.copyFile(tempDest, file);
				tempDest.delete();
				result.setData(filestr);
				return result;
			} catch (Exception ex) {
				ex.printStackTrace();
			}

		} else {

			String bathPath = WebUtils.getRealPath(req.getSession().getServletContext(), "/");
			Date now = new Date();
			String filestr = "upload/voice/" + now.getTime()
					+ moduleName.substring(moduleName.lastIndexOf("."), moduleName.length());
			File file = new File(bathPath, filestr);

			if (!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}

			try {
				File tempDest = new File(System.getProperty("java.io.tmpdir"),
						"upload_" + String.valueOf(System.nanoTime()) + ".tmp");
				imgFile.transferTo(tempDest); // 上传到临时文件中
				FileUtils.copyFile(tempDest, file);
				tempDest.delete();
				result.setData(filestr);
				return result;
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
		return ErrorMapV5.ERR_SYSTEM;
	}

	/**
	 * 跑腿升级创建订单.
	 * 
	 * @param passengerId
	 *            客户Id
	 * @param passengerName
	 *            客户姓名
	 * @param passengerPhone
	 *            客户电话
	 * @param companyId
	 *            公司Id
	 * @param companyName
	 *            公司名字
	 * @param channelName
	 *            订单来源
	 * @param startAddress
	 *            起点地址
	 * @param startLat
	 *            起点地址纬度
	 * @param startLng
	 *            起点地址经度
	 * @param deliverAddress
	 *            交付地址
	 * @param deliverLat
	 *            交付地纬度
	 * @param deliverLng
	 *            交付地经度
	 * @param startTime
	 *            预约时间
	 * @param startPrice
	 *            起步价
	 * @param mileagePrice
	 *            里程费
	 * @param travelTimePrice
	 *            时间费
	 * @param mileage
	 *            预计里程
	 * @param travelTime
	 *            预计时间
	 * @param shouldPay
	 *            预估价格
	 * @param couponId
	 *            优惠券id
	 * @param photos
	 *            附件图片
	 * @param orderTypeId
	 *            跑腿类型id
	 * @param content
	 *            任务文本
	 * @param appKey
	 *            区分系统
	 * @param recipients
	 *            收件人
	 * @param phone
	 *            收件人电话
	 * @param weight
	 *            重量
	 * @param buyNeeds
	 *            购买需求
	 * @param goodsCash
	 *            商品金额
	 * @param thanksCash
	 *            感谢费
	 * @param addServices
	 *            附加服务
	 * @param tips
	 *            热门标签
	 * @param startDetailed
	 *            详细开始地点
	 * @param endDetailed
	 *            详细结束地点
	 * @return 跑腿订单
	 */
	@ResponseBody
	@RequestMapping(value = { "createByPassenger" }, method = RequestMethod.POST)
	public ResponseEntity<Object> createByPassenger(
			HttpServletRequest req,
			@RequestParam("appKey") String appKey,
			@RequestParam("passengerId") Long passengerId,
			@RequestParam("passengerName") String passengerName, 
			@RequestParam("passengerPhone") String passengerPhone,
			@RequestParam("companyId") Long companyId, 
			@RequestParam("companyName") String companyName,
			@RequestParam("channelName") String channelName,
			@RequestParam(required = true, value = "prePay") boolean prePay,
			@RequestParam(required = true, value = "payType") String payType,
			@RequestParam(required = false, value = "startAddress") String startAddress,
			@RequestParam(required = false, value = "startLat") Double startLat,
			@RequestParam(required = false, value = "startLng") Double startLng,
			@RequestParam(required = false, value = "deliverAddress") String deliverAddress,
			@RequestParam(required = false, value = "deliverLat") Double deliverLat,
			@RequestParam(required = false, value = "deliverLng") Double deliverLng,
			@RequestParam(required = false, value = "startTime") Long startTime,
			@RequestParam(required = false, value = "startPrice") Double startPrice,
			@RequestParam(required = false, value = "mileagePrice") Double mileagePrice,
			@RequestParam(required = false, value = "travelTimePrice") Double travelTimePrice,
			@RequestParam(required = false, value = "mileage") Double mileage,
			@RequestParam(required = false, value = "travelTime") Integer travelTime,
			@RequestParam(required = false, value = "shouldPay") Double shouldPay,
			@RequestParam(required = false, value = "orderTypeId") Long orderTypeId,
			@RequestParam(required = false, value = "couponId") Long couponId,
			@RequestParam(required = false, value = "photos") String photos,
			@RequestParam(required = false, value = "content") String content,
			@RequestParam(required = false, value = "startDetailed") String startDetailed,
			@RequestParam(required = false, value = "endDetailed") String endDetailed,
			@RequestParam(required = false, value = "recipients") String recipients,
			@RequestParam(required = false, value = "phone") String phone,
			@RequestParam(required = false, value = "weight") String weight,
			@RequestParam(required = false, value = "matter") String matter,
			@RequestParam(required = false, value = "buyNeeds") String buyNeeds,
			@RequestParam(required = false, value = "goodsCash") Double goodsCash,
			@RequestParam(required = false, value = "thanksCash") Double thanksCash,
			@RequestParam(required = false, value = "addServices") String addServices,
			@RequestParam(required = false, value = "tips") String tips) {

		ResponseEntity<Object> responseEntity = null;
		WxApplication wxApplication = wxApplicationManager.findByAppKey(appKey);
		try {
			appKey = StringUtils.trimToEmpty(appKey);
			Preconditions.checkArgument(StringUtils.isNotBlank(appKey), "AppKey不能为空");

			if (!payType.equals(Order.PayTypeDetails.coupon.toString())
					&& !payType.equals(Order.PayTypeDetails.sign.toString())
					&& !payType.equals(Order.PayTypeDetails.balance.toString())) {
				Error error = new Error(-1, "支付方式应为优惠券、余额或签单支付");
				responseEntity = new ResponseEntity<Object>(error, HttpStatus.OK);
				return responseEntity;
			}

			if (StringUtils.isNotBlank(content) && content.length() > 200) {
				Error error = new Error(-41, "内容长度过长");
				responseEntity = new ResponseEntity<Object>(error, HttpStatus.OK);
				return responseEntity;
			}
			if (null == companyId || StringUtils.isBlank(companyName)) {
				Error error = new Error(-1, "参数错误:公司不能为空");
				responseEntity = new ResponseEntity<Object>(error, HttpStatus.OK);
				return responseEntity;
			}
			if (passengerId == null || passengerId == 0) {
				Error error = new Error(-20, "参数错误:客户不存在");
				responseEntity = new ResponseEntity<Object>(error, HttpStatus.OK);
				return responseEntity;
			}
			if (!PhoneNumberHelper.isPhoneNumber(passengerPhone)) {
				Error error = new Error(-1, "参数错误:电话号码格式不正确");
				responseEntity = new ResponseEntity<Object>(error, HttpStatus.OK);
				return responseEntity;
			}

			Passenger passenger = passengerApi.findById(passengerId, appKey);
			// 并行单量判断
			Long count = errandManager.countNotFinishedByPassenger(passengerId, appKey);
			Long number = 1L;
			if (null != passenger.getPassengerGrade() && passenger.getPassengerGrade().getParallelOrderNumber() > 0
					&& count + number > passenger.getPassengerGrade().getParallelOrderNumber()) {
				Error error = new Error(-86, "您当前有" + count + "个订单未结束!不能再下新单。");
				responseEntity = new ResponseEntity<Object>(error, HttpStatus.OK);
				return responseEntity;
			}

			JSONObject object = daijiaApi.getServices(wxApplication.getAddress());
			if (object != null) {
				Long num = 0L;
				boolean daijia = object.getBooleanValue("daijia");
				if (daijia) {
					num += daijiaApi.countNotPayAmounts(wxApplication.getAddress(), passengerId);
				}
				boolean zhuanche = object.getBooleanValue("zhuanche");
				if (zhuanche) {
					num += zhuanApi.countNotPayAmounts(passengerId, appKey);
				}
				boolean paotui = object.getBooleanValue("paotui");
				if (paotui) {
					num += errandManager.countNotPayAmounts(passengerId, appKey);
				}
				boolean freight = object.getBooleanValue("freight");
				if (freight) {
					num += freightManager.countNotPayAmounts(passengerId, appKey);
				}
				boolean zhuanxian = object.getBooleanValue("zhuanxian");
				if (zhuanxian) {
					num += zhuanXianApi.countNotPayAmounts(passengerId, appKey);
				}
				if (num > 0) {
					Error error = new Error(-54, "还有未完成支付的订单，不能下单");
					responseEntity = new ResponseEntity<Object>(error, HttpStatus.OK);
					return responseEntity;
				}
			}

//			Long countRunning = errandManager.countRunning(passengerId, appKey);
//			if (countRunning > 10) {
//				Error error = new Error(-55, "您今日下单已达到上限，继续下单请联系客服");
//				responseEntity = new ResponseEntity<Object>(error, HttpStatus.OK);
//				return responseEntity;
//			}

			String address = wxApplication.getAddress();// 代驾地址

			// 判断余额是否够等。。
			if (prePay) {
				ResultVo balancesignPayCheck = daijiaApi.balancesignPayCheck(address, shouldPay, passengerId, payType, couponId);
				if (!balancesignPayCheck.isSuccess()) {
					Error error = new Error(-1, balancesignPayCheck.getMessage());
					responseEntity = new ResponseEntity<Object>(error, HttpStatus.OK);
					return responseEntity;
				}
			}

			Date startDate = null;
			if (null != startTime) {
				startDate = new Date(startTime);// 开始时间
			}

			Order order = errandManager.saveOrder(passengerId, passengerName, passengerPhone, companyId, companyName,
					startAddress, startLat, startLng, deliverAddress, deliverLat, deliverLng, channelName, startDate,
					startPrice, mileagePrice, travelTimePrice, mileage, travelTime, shouldPay, orderTypeId, couponId,
					content, null, null, null, null, null, null, appKey, startDetailed, endDetailed, recipients, phone,
					weight, buyNeeds, goodsCash, thanksCash, addServices, tips, matter, prePay, payType, address);

			String basePath = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort()
					+ req.getContextPath();

			if (StringUtils.isNotBlank(photos)) {
				errandManager.saveOrderImgs(order.getId(), channelName, photos, appKey);
			}
			if (null != order.getId()) {
				daijiaApi.pushNewOrder(address, order.getId());
			}
			Map<String, Object> returnMap = new HashMap<String, Object>();
			returnMap.put("orderId", order.getId());
			Result<Map<String, Object>> result = new Result<Map<String, Object>>(0, "成功", returnMap);
			responseEntity = new ResponseEntity<Object>(result, HttpStatus.CREATED);

			return responseEntity;

		} catch (Exception ex) {
			Error error = new Error(-4, "内部服务器错误：" + ex.getMessage());
			responseEntity = new ResponseEntity<Object>(error, HttpStatus.INTERNAL_SERVER_ERROR);
			return responseEntity;
		}
	}

	/**
	 * 微信支付.
	 * 
	 * @param appKey 系统key
	 * @param orderId 订单id
	 * @param openId 微信id
	 * @param appId 微信应用id
	 * @param request 判断是否来自微信
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "doPayForWx", method = RequestMethod.POST)
	public ResultV5 doPayForWx(@RequestParam(required = true, value = "appKey") String appKey,
			@RequestParam(required = true, value = "orderId") Long orderId,
			@RequestParam(required = true, value = "openId") String openId,
			@RequestParam(required = true, value = "appId") String appId, HttpServletRequest request) {

		ResultV5 result = null;
		try {
			WxApplication wxApplication = wxApplicationManager.findByAppKey(appKey);
			Preconditions.checkArgument(null != wxApplication, "appKey错误");

			WxAccount wxAccount = wxAccountManager.findBy(appId, wxApplication.getId());
			Preconditions.checkArgument(null != wxAccount, "appid错误");

			// 判断是否来自微信
			StringBuilder sb = new StringBuilder();
			sb.append(request.getScheme());
			sb.append("://");
			sb.append(request.getServerName());
			int port = request.getServerPort();
			if (port != 80) {
				sb.append(":").append(port);
			}
			sb.append(request.getRequestURI());
			String queryString = request.getQueryString();
			if (StringUtils.isNotBlank(queryString)) {
				sb.append("?");
				sb.append(queryString);
			}

			JSONObject jsonObject = new JSONObject();
			JSONObject jo = daijiaApi.getPtWxPrepayId(wxApplication.getAddress(), orderId, openId);
			jsonObject.put("package", jo.getString("package"));
			jsonObject.put("timestamp", jo.getString("timeStamp"));
			jsonObject.put("url", sb.toString());
			jsonObject.put("nonceStr", jo.getString("nonceStr"));
			jsonObject.put("paySign", jo.getString("paySign"));

			// 获取微信AccessToken
			String response = restTemplate.getForObject(WX_ACCESS_TOKEN, String.class, wxAccount.getWxappId(),
					wxAccount.getAppsecret());
			JSONObject ac = JSON.parseObject(response);
			if (ac.containsKey("access_token")) {
				String accessToken = ac.getString("access_token"); // 获取微信access_token
				// 获取jsapi_ticket
				String resp = restTemplate.getForObject(WX_JSAPI_TICKET, String.class, accessToken);
				JSONObject ticketJson = JSON.parseObject(resp);
				if (ticketJson.containsKey("ticket")) {
					String ticket = ticketJson.getString("ticket");
					jsonObject.put("jsapi_ticket", ticket);
					Map<String, Object> signParams = new HashMap<>();
					signParams.put("jsapi_ticket", ticket);
					signParams.put("timestamp", jo.getString("timeStamp"));
					signParams.put("url", sb.toString());
					signParams.put("noncestr", jo.getString("nonceStr"));
					jsonObject.put("signature", WxUtils.buildSha1Sign(signParams));

					result = ErrorMapV5.ERR_SUCCESS.clone();
					result.setData(jsonObject);
					return result;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return ErrorMapV5.ERR_SYSTEM;
		}
		return ErrorMapV5.ERR_GET_WECHAT_PAY_PARAMS;
	}
}
